﻿using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using static LeafTransmission.Utils.AsyncUDPClient;
using static System.Windows.Forms.AxHost;

namespace LeafTransmission.Utils
{
    /// <summary>
    /// 基于UDPClient封装的异步UDP客户端
    /// </summary>
    internal class AsyncUDPClient
    {
        public struct AsyncUdpState
        {
            public UdpClient workClient;
            /*public IPAddress ipAddress;
            public int port;*/
            public IPEndPoint remoteEndPoint;
            public byte[] data;
        }
        #region 常量 字段 属性
        // 默认服务启动的端口
        public static readonly int DEFAULT_SERVER_PORT = 9988;

        // 用于UDP上线的特殊标识符
        public static readonly string ONLINE_SIGNAL = "I@M&COMING$";

        private UdpClient _udpClient;

        private bool _disposed = false;


        // 服务器是否正在运行
        public bool IsRunning { get; private set; }
        // 监听的IP地址
        public IPAddress Address { get; private set; }
        /*
         * 监听的端口
         * 客户端 8899
         * 服务端 9988
         */
        public int Port { get; private set; } = DEFAULT_SERVER_PORT;
        // 通信过程使用的编码, 默认Unicode
        public Encoding Encoding { get; set; } = Encoding.Unicode;
        #endregion

        #region 构造函数
        public AsyncUDPClient() : this(IPAddress.Any, DEFAULT_SERVER_PORT, Encoding.Unicode)
        { }
        public AsyncUDPClient(IPEndPoint iPEndPoint)
            : this(iPEndPoint.Address, iPEndPoint.Port, Encoding.Unicode) { }
        public AsyncUDPClient(IPAddress ipAddress, int listenPort, Encoding encoding)
        {
            Address = ipAddress;
            Port = listenPort;
            Encoding = encoding;

            // 初始化udpClient
            _udpClient = new UdpClient(new IPEndPoint(Address, Port));
        }
        #endregion

        #region 公有方法

        /// <summary>
        /// 开启服务. 
        /// 需注意: UdpClient是在构造函数时创建. 开启服务的同时开始接收数据
        /// </summary>
        public void StartServer()
        {
            if (!IsRunning)
            {
                IsRunning = true;
                _udpClient.EnableBroadcast = true;
                
                // _udpClient.BeginReceive(new AsyncCallback(ReceiveCompletedCallback), null);
            }
        }

        public void Stop()
        {
            if (IsRunning && _udpClient != null)
            {
                IsRunning = false;
                _udpClient.Close();
                _udpClient.Dispose();
            }
        }

        // 开始异步接收消息
        public void BeginAsyncReceive()
        {
            AsyncUdpState state = new AsyncUdpState();
            state.workClient = _udpClient;
            IPEndPoint iPEndPoint = new IPEndPoint(Address, Port);
            state.remoteEndPoint = iPEndPoint;

            _udpClient.BeginReceive(new AsyncCallback(ReceiveCompletedCallback), state);
        }

        private void ReceiveCompletedCallback(IAsyncResult ar)
        {
            if (ar == null) { return; }
            AsyncUdpState state = (AsyncUdpState)ar.AsyncState;
            UdpClient client = state.workClient;
            IPEndPoint iPEndPoint = state.remoteEndPoint;

            try
            {
                byte[] receiveBytes = _udpClient.EndReceive(ar, ref iPEndPoint);

                // 普通数据接收成功!
                RaiseDataReceived(_udpClient, iPEndPoint, receiveBytes, true, "success");

                /*if (!(ONLINE_SIGNAL == Encoding.GetString(receiveBytes, 0, receiveBytes.Length)))
                {
                    // 普通数据接收成功!
                    RaiseDataReceived(client, iPEndPoint, receiveBytes, true, "success");
                }
                else
                {
                    // 上线信号接收成功!
                    RaiseOnlineSignalReceived(client, iPEndPoint, true);
                }*/

                // MessageBox.Show(Encoding.GetString(receiveBytes, 0, receiveBytes.Length));
                
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message.ToString());
                /*RaiseDataReceived(client, iPEndPoint, null, false, ex.ToString());
                RaiseOnlineSignalReceived(client, iPEndPoint, false);*/
            }
            finally
            {
                if (IsRunning && _udpClient != null)
                {
                    // 重复调用
                    BeginAsyncReceive();
                }
            }
        }

        /// <summary>
        /// 发送消息
        /// </summary>
        /// <param name="message"></param>
        /// <param name="remote"></param>
        public void BeginAsyncSendMsg(string message, IPEndPoint remote)
        {
            byte[] data = Encoding.GetBytes(message);
            AsyncUdpState state = new AsyncUdpState();
            state.workClient = _udpClient;
            state.remoteEndPoint = remote;
            state.data = data;

            try
            {

                _udpClient.BeginSend(data, data.Length, remote, new AsyncCallback(SendCompletedCallback), state);

                /*if (message != ONLINE_SIGNAL)
                {
                    _udpClient.BeginSend(data, data.Length, remote, new AsyncCallback(SendCompletedCallback), state);
                }
                else
                {
                    _udpClient.BeginSend(data, data.Length, remote, new AsyncCallback(SendOnlineSignalCompleted), state);
                }*/
                
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }

        }

        /// <summary>
        /// 发送上线信号
        /// </summary>
        /// <param name="remote">远程主机地址与目标端口号</param>
        public void BeginAsyncSendOnlineSignal(IPEndPoint remote)
        {
            BeginAsyncSendMsg(ONLINE_SIGNAL,remote);
        }

        public void SendOnlineSignalCompleted(IAsyncResult result)
        { 
        }


        public void BeginAsyncSendDatagram(byte[] datagram, IPEndPoint remote)
        {
        }

        private void SendCompletedCallback(IAsyncResult result)
        {
            if (result.IsCompleted)
            {
                AsyncUdpState state = (AsyncUdpState)result.AsyncState;
                UdpClient client = state.workClient;
                IPEndPoint iPEndPoint = state.remoteEndPoint;
                byte[] data = state.data;
                try
                {
                    _udpClient.EndSend(result);
                    // 消息发送完毕事件
                    RaiseCompletedSend(client, iPEndPoint, data, true, null);
                }
                catch (Exception ex)
                {
                    // MessageBox.Show(ex.Message);
                    // 消息发送失败,将失败信息传递
                    RaiseCompletedSend(client, iPEndPoint, data, false, ex.ToString());
                }


            }
        }
        #endregion
        #region 事件
        /// <summary>
        /// 接收到数据事件
        /// </summary>
        public event EventHandler<AsyncUDPClientEventArgs> DataReceived;
        // 触发接收到数据事件
        private void RaiseDataReceived(UdpClient workClient, IPEndPoint ipEndPoint, byte[] bufferData, bool success, string executeMessage)
        {
            
            if (DataReceived != null)
            {
                /*DataReceived.Invoke(this, 
                    new AsyncUDPClientEventArgs(workClient, ipEndPoint, bufferData, success, executeMessage));*/
                // sender e
                DataReceived(this,
                    new AsyncUDPClientEventArgs(workClient, ipEndPoint, bufferData, success, executeMessage));
            }
        }

        /// <summary>
        /// 接收到上线信号的事件
        /// </summary>
        public event EventHandler<AsyncUDPClientEventArgs> OnlineSignalReceived;
        // 触发接收到数据事件
        private void RaiseOnlineSignalReceived(UdpClient workClient, IPEndPoint ipEndPoint, bool success)
        {
            if (OnlineSignalReceived != null)
            {
                OnlineSignalReceived.Invoke(this, new AsyncUDPClientEventArgs(workClient, ipEndPoint, success));
                // sender e
                // OnlineSignalReceived(this, new AsyncUDPClientEventArgs(workClient, ipEndPoint, success));
            }
        }

        /// <summary>
        /// 数据发送完毕事件
        /// </summary>
        public event EventHandler<AsyncUDPClientEventArgs> CompletedSend;
        // 触发数据发送完毕事件
        private void RaiseCompletedSend(UdpClient workClient, IPEndPoint ipEndPoint, byte[] bufferData, bool success, string executeMessage)
        {
            if (CompletedSend != null)
            {
                CompletedSend.Invoke(this, new AsyncUDPClientEventArgs(workClient, ipEndPoint, bufferData, success, executeMessage));
            }
        }
        #endregion
    }
}
